package com.fs.sys.entityservice.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fs.common.base.service.AbstractSimpleEntityService;
import com.fs.common.bean.UserContext;
import com.fs.common.exception.AppException;
import com.fs.common.exception.AuthErrorCodes;
import com.fs.sys.bean.dto.TenantUserDTO;
import com.fs.sys.bean.dto.UserDTO;
import com.fs.sys.bean.dto.UserRoleDTO;
import com.fs.sys.bean.enums.UserStatus;
import com.fs.sys.bean.query.NoRoleUserQuery;
import com.fs.sys.bean.query.UserQuery;
import com.fs.common.ErrorCodes;
import com.fs.sys.domain.entity.UserEntity;
import com.fs.sys.domain.mapper.UserMapper;
import com.fs.sys.entityservice.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

import static com.fs.common.ErrorCodes.BASE_USER_PHONE_EXISTS;

@Service
public class UserEntityServiceImpl extends AbstractSimpleEntityService<UserEntity, UserDTO, UserMapper, UserQuery> implements UserEntityService {
    @Autowired
    private UserRoleEntityService userRoleEntityService;

    @Autowired
    @Lazy
    private PasswordEncoder passwordEncoder;

    @Autowired
    private DeptEntityService deptEntityService;

    @Autowired
    private RoleResourceEntityService roleResourceEntityService;

    @Autowired
    private TenantUserEntityService tenantUserEntityService;

    @Override
    protected QueryWrapper<UserEntity> queryToWrapper(UserQuery userQuery) {
        return this.createQueryWrapper()
                .in(null != userQuery.getIds(), "u.id", userQuery.getIds())
                .notIn(null != userQuery.getIdsNotIn(), "u.id", userQuery.getIdsNotIn())
                .eq(StringUtils.isNotBlank(userQuery.getId()), "u.id", userQuery.getId())
                .eq(StringUtils.isNotBlank(userQuery.getUsername()), "u.username", userQuery.getUsername())
                .eq(StringUtils.isNotBlank(userQuery.getPhone()), "u.phone", userQuery.getPhone())
                .eq(StringUtils.isNotBlank(userQuery.getEmail()), "u.email", userQuery.getEmail())
                .eq(StringUtils.isNotBlank(userQuery.getDeptId()), "u.dept_id", userQuery.getDeptId())
                .eq(StringUtils.isNotBlank(userQuery.getTenantId()), "t.tenant_id", userQuery.getTenantId())
                .eq(StringUtils.isNotBlank(userQuery.getCode()), "u.code", userQuery.getCode())
                .and(StringUtils.isNotBlank(userQuery.getKey()), wrapper ->
                        wrapper.eq("u.username", userQuery.getKey())
                                .or(q -> q.eq("u.phone", userQuery.getKey()))
                                .or(q -> q.eq("u.email", userQuery.getKey())));
    }

    @Override
    protected boolean processBeforeInsert(UserDTO dto) {
        // 校验用户名、手机号、邮箱是否存在
        String username = dto.getUsername();
        String phone = dto.getPhone();
        if (this.userExists(username, phone)) {
            throw AppException.of(ErrorCodes.BASE_USER_USERNAME_OR_PHONE_EXISTS);
        }

        if (StringUtils.isEmpty(dto.getNickname())) {
            dto.setNickname(dto.getUsername());
        }

        if (StringUtils.isEmpty(dto.getPassword())) {
            dto.setPassword(dto.getPhone().substring(5));
        }

        dto.setPassword(passwordEncoder.encode(dto.getPassword()));

        dto.setIsSuperAdmin(false);
        dto.setStatus(UserStatus.VALID);

        return true;
    }

    @Override
    protected boolean processBeforeUpdate(UserDTO dto) {
        // 更新前检查手机号是否重复
        String id = dto.getId();
        String phone = dto.getPhone();
        if (!StringUtils.isEmpty(phone)) {
            this.findByPhone(phone).ifPresent(e -> {
                if (!e.getId().equals(id)) {
                    throw AppException.of(BASE_USER_PHONE_EXISTS);
                }
            });
        }

        return true;
    }

    /**
     * 查询后处理
     *
     * @param list 查询结果
     */
    @Override
    protected void processAfterQuery(List<UserDTO> list) {
        super.processAfterQuery(list);

        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        // 补充用户角色、机构信息
        List<String> deptIds = new ArrayList<>(16);
        List<String> userIds = list.stream()
                .peek(user -> {
                    if (!StringUtils.isEmpty(user.getDeptId())) {
                        deptIds.add(user.getDeptId());
                    }
                })
                .map(UserDTO::getId)
                .toList();
        List<UserRoleDTO> userRoles = userRoleEntityService.findByUsers(userIds);
        Map<String, List<String>> userRoleMap = new HashMap<>(16);
        if (!CollectionUtils.isEmpty(userRoles)) {
            userRoles.forEach(userRole -> {
                String userId = userRole.getUserId();
                userRoleMap.computeIfAbsent(userId, n -> new ArrayList<>(16))
                        .add(userRole.getRoleId());
            });
        }

        // 查询用户机构名称
        Map<String, String> deptNameMap = new HashMap<>(16);
        if (!CollectionUtils.isEmpty(deptIds)) {
            deptEntityService.findByIds(deptIds)
                    .forEach(dept -> deptNameMap.put(dept.getId(), dept.getName()));
        }

        list.forEach(user -> {
            user.setRoleIds(userRoleMap.get(user.getId()));
            if (null != user.getDeptId()) {
                user.setDeptName(deptNameMap.get(user.getDeptId()));
            }
        });
    }

    @Override
    public Optional<UserDTO> findByUsername(String username) {
        UserQuery query = new UserQuery();
        query.setUsername(username);
        return this.query(query).stream().findAny();
    }

    @Override
    public Optional<UserDTO> findByPhone(String phone) {
        UserQuery query = new UserQuery();
        query.setPhone(phone);
        return this.query(query).stream().findAny();
    }

    /**
     * 根据用户名、手机号判断用户是否存在
     */
    @Override
    public boolean userExists(String username, String phone) {
        QueryWrapper<UserEntity> query = this.createQueryWrapper().eq("username", username)
                .or(q -> q.eq("phone", phone));
        return this.count(query) > 0;
    }

    /**
     * 查询无指定角色的用户
     *
     * @param query 查询条件
     * @return 查询结果
     */
    @Override
    public List<UserDTO> queryUserNoRole(NoRoleUserQuery query) {
        return baseMapper.queryUserNoRole(query);
    }

    @Override
    public UserContext loadUserByUsername(String username) throws UsernameNotFoundException {
        return this.findByUsername(username)
                .map(user -> {
                    UserContext userContext = new UserContext();
                    BeanUtils.copyProperties(user, userContext);
                    userContext.setUserId(user.getId());

                    if (StringUtils.isBlank(user.getCurrentTenantId())) {
                        List<TenantUserDTO> list = tenantUserEntityService.findByUser(user.getId());
                        user.setCurrentTenantId(list.get(0).getTenantId());
                    }

                    userContext.setTenantId(user.getCurrentTenantId());

                    // 补充用户权限相关内容，包括：用户身份及用户角色相关信息
                    List<SimpleGrantedAuthority> authorityList = new ArrayList<>(16);
                    userContext.setAuthorities(authorityList);
                    if (user.getIsSuperAdmin()) {
                        // 兼容hasAuthority及hasRole两种使用方式
                        authorityList.add(new SimpleGrantedAuthority("admin"));
                        authorityList.add(new SimpleGrantedAuthority("ROLE_admin"));
                    } else {
                        authorityList.add(new SimpleGrantedAuthority("user"));
                    }

                    // 补充权限信息 // 暂不实现

                    return userContext;
                }).orElseThrow(() -> AppException.of(AuthErrorCodes.USERNAME_OR_PASSWORD_ERROR));
    }

    @Override
    public List<UserEntity> list(Wrapper<UserEntity> queryWrapper) {
        // 覆盖原实现，增加租户id查询条件
        return baseMapper.customSelectList(queryWrapper);
    }

    @Override
    public <E extends IPage<UserEntity>> E page(E page, Wrapper<UserEntity> queryWrapper) {
        return baseMapper.customSelectPage(page, queryWrapper);
    }
}
